﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MathNet.Numerics.Distributions;
using Microsoft.Xna.Framework;

namespace GodPl.GameObjects.Creatures
{
    public class Genes
    {
        /// <summary>
        /// Default value for a gene
        /// </summary>
        static float defaultValue = 0.5f;

        #region Randomization


        /// <summary>
        /// Standard deviation to use for randomizing gene values
        /// </summary>
        static float standardDeviation = 0.07f;

        /// <summary>
        /// Normal distribution generator
        /// </summary>
        static NormalDistribution normalDist = new NormalDistribution(0.5, (double)standardDeviation);

        public static float StandardDeviation
        {
            get { return standardDeviation; }
            set { standardDeviation = value; normalDist.Sigma = standardDeviation; }
        }


        #endregion

        Briyya briyya;

        public Briyya Briyya
        {
            get { return briyya; }
            set { briyya = value; }
        }


        /// <summary>
        /// Array of genes
        /// </summary>
        float[] values = new float[Genes.NumGenes];
        Sex sex;

        public Genes(Briyya briyya, Sex sex, bool randomizeGenes)
        {
            this.briyya = briyya;
            Initialize(sex, true);
        }

        /// <summary>
        /// Initialize all genes with default value
        /// </summary>
        public void Initialize(Sex sex, bool randomize)
        {
            normalDist = new NormalDistribution(0, (double)standardDeviation);
            this.sex = sex;

            foreach (GeneName gene in Enum.GetValues(typeof(GeneName)))
            {
                this[gene] = defaultValue;

                if (randomize)
                {
                    this[gene] = this[gene] + (float)normalDist.NextDouble();
                }
            }


            // The colors need some more variety
            if (randomize)
            {
                this[GeneName.ColorRed] = (float)GodPlGame.RandomGen.NextDouble();
                this[GeneName.ColorGreen] = (float)GodPlGame.RandomGen.NextDouble();
                this[GeneName.ColorBlue] = (float)GodPlGame.RandomGen.NextDouble();
            }
        }

        /// <summary>
        /// Returns a new Geneset that features the combined 
        /// </summary>
        /// <param name="a">Geneset of parent a</param>
        /// <param name="b">Geneset of parent b</param>
        /// <returns></returns>
        public static Genes Recombine(Genes a, Genes b)
        {
            Genes result = new Genes(null, RandomSex(), false);

            foreach (GeneName gene in Enum.GetValues(typeof(GeneName)))
            {
                result[gene] = (a[gene] + b[gene]) / 2.0f + (float)normalDist.NextDouble();
            }

            return result;
        }

        /// <summary>
        /// Get the number of genes in the genes
        /// </summary>
        public static int NumGenes
        {
            get { return Enum.GetValues(typeof(GeneName)).Length; }
        }

        public static Sex RandomSex()
        {
            return (GodPlGame.RandomGen.Next() % 2 == 0 ? Sex.Male : Sex.Female);
        }

        


        public float this[GeneName gene]
        {
            get { return values[(int)gene]; }
            private set { values[(int)gene] = MathHelper.Clamp(value, 0f, 1f); }
        }

        /// <summary>
        /// Returns the sex that's part of the genes. Keep comments about the property's declaration to yourself.
        /// </summary>
        public Sex Sex
        {
            get { return sex; }
        }


    }

    public enum GeneName
    {
        ColorRed, ColorBlue, ColorGreen, SizeScale, Swiftness,
        Curiosity, Aggressiveness, Courage,
        ResistanceToCold, ResistanceToToxin, ResistanceToPain,
        Strength, Longevity
    };

    public enum Sex { Male, Female };
}
